Skip to main content

tokenized-asset-contracts

Tokenized Asset Contracts
Made with ❤ by ITEM Systems

0 - Overview

This document outlines what a tokenized asset contract is and how to create one that allows you to create a physical tokenize object that operates in the ITEM Systems ecosystem. This document also outlines a standard for required and optional contract operations as well as some ideas for interesting utility.

1 - What is a Tokenized Asset Contract?

In order to maximize the autonomy of "vendors" and provide them with the ability to offer bespoke features in their products in addition to NFI capabilities, we have chosen to architecturally isolate the tokenization and authentication features in the ecosystem. This allows anyone to easily create and manage their own non-fungible token collections which have a physical asset that is bound to it. For illustrative purposes, we'll use an example where the tokenized asset contract is an extension of a Non-Fungible Token contract, but this is not a strict architectural requirement in the ecosystem.

2 - Creating a Tokenized Asset Contract

Creating or converting a non-fungible contract as a tokenized asset contract is simple and self-custodial using the following workflow:

**Note: Examples are provided in typescript and python (boa) for Neo N3, but are applicable for all languages and protocols.*

2.1.a - Define a manufacturing configuration

This is a recommended step associated with the manufacturing of physical assets. We recommend engaging an NFI manufacturer to define production configurations and terms before minting items in step 2. Production of your required hardware configuration is a parallel process to steps 1 and 2.

**Note: If you require the NFIs to be available at the time of minting, we STRONGLY advise contacting the ITEM Systems team as early as possible to ensure on-time deliver of your configuration.

2.1.b - Bind your contract to an epoch

The first step is to create a new epoch for your contract. We recommend maintaining one epoch for each "collection" so if your contract supports multiple collections, a more advanced pattern using multiple epochs may be required. For existing projects, a linking contract can be used to convert them into a tokenized asset contract.

Automated Binding

From your smart contract, call the createEpoch() -> int method on the item({{SCRIPT_HASH}}) contract and save the response as your local epoch-id (local_eid).

For new contracts, we recommend overloading your deploy method and including the binding there:

from typing import Any
from boa3.sc.storage import put
from boa3.sc.utils import call_contract, to_bytes
from cpm_out.onchain.python.item.contract import Item

@public
def _deploy(data: Any, update: bool):
local_eid: int = Item.createEpoch()
put(to_bytes("EPOCH_ID"), to_bytes(local_eid))

**Note: Python snippets assume use of CPM, which is installed with neo3-boa*

2.1.c - Mint Items

From your smart contract, call the createItem(local_eid: int) -> int method on the Item({{SCRIPT_HASH}}) contract and save the response as the local non-fungible item identifier (local_nfid).

We recommend adding the contract call to your token minting workflow, then saving the resulting local_nfid to the token properties.


@public
def mint() -> int:
local_eid_bytes: bytes = get(to_bytes("EPOCH_ID"))
local_nfid: int = Item.createItem(to_int(local_eid_bytes))

return mint_my_token(local_nfid)

For a reference implementation, refer to the AeroGlyph contract.

2.1.d - Engage a Manufacturer to bind assets

Currently, the primary manufacturer is ITEM Systems proper. We can be engaged here or through the COZ discord.

3 - Specification

ownerOf(tokenId: bytes) -> UInt160`
"""
(Required)
Gets the owner of a token.
:param tokenId the unique byte formatted token identifier
:return the UInt160 formatted address of the token owner
"""
isItemClaimable(tokenId: bytes) -> List[bytes]`
"""
(Required)
Communicates if an individual tokenized asset can be claimed by providing an interaction proof.
This value will a static [] if the contract does not implement the "Bind on Pickup" workflow.
:param: tokenId the unique tokenized asset id to check
:return a byte array representing the required protocols for claiming the tokenized asset.
"""
setClaimableState(tokenId: bytes, state: bool) -> bool
"""
(Optional)
Sets the NFI claimable state for the asset.
claim(tokenId: bytes, authPayload: List[bytes]) -> bool
"""
(Optional)
Sets the owner of "tokenId" to the transaction signer if the interaction proof is valid. This method should trigger
all relevant events associated with transfering ownership of the token for other supported standards.
:param tokenId the unique tokenized asset to claim ownership of
:param authPayload the payload required to solve the challenge method
"""

3 - Workflows

3.1 - Bind on Pickup

This workflow allows a user to claim ownership of a non-fungible item by proving that they have interacted with it. There are a few different ways this can work. We will outline the basic flow first, then provide some advanced considerations.

  1. On mint, set the isItemClaimable flag for each tokenId to [b'\x01'] (Permissive Integer Locked Signature)
  2. Produce the physical asset in coordination with the manufacturer (2.1.d) and bind them to the tokenized asset
  3. Distribute the NFIs through your preferred channel
  4. When the new owner tap scans the asset, they will be presented with our internal claim workflow, which allows them to invoke your claimItem method with the relevant fields.
  5. Your claimItem method should adhere to the following:
    claimItem(tokenId: bytes, message: bytes, proof: bytes, challenge: bytes) -> bool
    local_nfid: int = method_to_lookup_the_nfid(tokenId)
    If token_is_claimable and challenge in token_claimable_challenges:
    Item.authItem(local_nfid, message, proof, b'\x01', True)
    method_to_set_owner(tx.sender)
    method_to_set_claimable(False)
    return True
    return False